package com.googlecode.gwtbb.server.intermediate.forum;

import com.googlecode.gwtbb.client.shared.entity.forum.Post;
import com.googlecode.gwtbb.client.shared.entity.user.User;
import com.googlecode.gwtbb.server.dao.forum.PostDao;
import com.googlecode.gwtbb.server.dao.forum.PostInfoDao;
import com.googlecode.gwtbb.server.dao.user.UserDao;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Jul 7, 2008
 */
public class PostAssembler {
	private PostDao postDao;
	private PostInfoDao postInfoDao;
	private UserDao userDao;

	public PostDao getPostDao() {
		return postDao;
	}

	public void setPostDao(PostDao postDao) {
		this.postDao = postDao;
	}

	public PostInfoDao getPostInfoDao() {
		return postInfoDao;
	}

	public void setPostInfoDao(PostInfoDao postInfoDao) {
		this.postInfoDao = postInfoDao;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}

	@Transactional
	public Post assemble(Long postId) {
		return assemble(postDao.select(postId));
	}

	@Transactional
	public Post assemble(Post post) {
		Map<Long, Post> postMap = new HashMap<Long, Post>(4);
		Map<Long, User> userMap = new HashMap<Long, User>(4);

		return doAssemble(post, postMap, userMap);
	}

	@Transactional
	public List<Post> assemble(List<Post> posts) {
		int initialCapacity = posts.size() * 2;
		Map<Long, Post> postMap = new HashMap<Long, Post>(initialCapacity);
		Map<Long, User> userMap = new HashMap<Long, User>(initialCapacity);

		for (Post post : posts)
			doAssemble(post, postMap, userMap);

		return posts;
	}

	@Transactional
	protected Post doAssemble(Post post, Map<Long, Post> postMap, Map<Long, User> userMap) {
		if (post != null) {
			postMap.put(post.getId(), post);
			Post.Info postInfo = post.getInfo();
			if (postInfo == null) {
				Long postId = post.getId();
				postInfo = postInfoDao.select(postId);
				post.setInfo(postInfo);
				Long lastPostInThreadId = postInfo.getLastPostInThreadId();
				Post lastPostInThread = postMap.get(lastPostInThreadId);
				if (lastPostInThread == null)
					lastPostInThread = doAssemble(postDao.select(lastPostInThreadId), postMap, userMap);
				postInfo.setLastPostInThread(lastPostInThread);
				Long threadId = post.getThreadId();
				Post thread = postMap.get(threadId);
				if (thread == null)
					thread = doAssemble(postDao.select(threadId), postMap, userMap);
				postInfo.setThread(thread);
				Long userId = post.getUserId();
				User user = userMap.get(userId);
				if (user == null) {
					user = userDao.selectSansPassword(userId);
					userMap.put(userId, user);
				}
				postInfo.setUser(user);
			}
		}
		return post;
	}
}
